/**
 *  Copyright Matt Silbernagel 2010`
 *  
 *	This file is part of MobilePrinting.
 *
 *	MobilePrinting is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  MobilePrinting is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with MobilePrinting.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.uc.labs.MobilePrinting;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.xml.sax.SAXException;

import Exceptions.OperatingSystemNotSupportedException;

import edu.uc.labs.MobilePrinting.OSUtils.Installer;
import edu.uc.labs.MobilePrinting.Prefs.Preferences;
import edu.uc.labs.MobilePrinting.Prefs.PreferencesParser;

/**
 * 
 * @author Matt Silbernagel
 */
public class Configurator {
	
	// Current Zone - initialize to null
	private static String currentZone = null;
	
	// App Version
	public static String VERSION = "2.00.04";
	
	// System Properties
	final public static String OS = System.getProperty("os.name");
	final public static String homeDir = System.getProperty("user.home");
	final public static String WORKINGDIR = System.getProperty("user.dir");
	final public static String DELIM = getDelim();
	
	// Sleep Config
	public final static int SLEEP = 10000;
	final static int SLEEP_LONG = 30000;

	// Absolute Path to the UserSpace
	final public static String USERSPACE = getCache("user");
	
	// Absolute Path to the SystemSpace
	final public static String SYSTEMSPACE = getCache("system"); 
	
	// Directories that need
	// to be created in UserSpace
	final public static String CACHE = USERSPACE + "cache";
	final public static String PREFS = USERSPACE + "preferences";
	final public static String LOGS  = USERSPACE + "logs";
	
	// Directories that need
	// to be created in SystemSpace

	final public static String PPD     = SYSTEMSPACE + "ppd";
	final public static String ICONS   = SYSTEMSPACE + "icons";
	final public static String DRIVERS = SYSTEMSPACE + "drivers";
	final public static String SCRIPTS = SYSTEMSPACE + "scripts";
	final public static String LIBS    = SYSTEMSPACE + "libs";
	
	// Preferences set by default
	public static String STARTUP_SCRIPT = "_startup";
	public static String PRINTERNAME = "MobilePrinter";
	public static String HTTP_SERVER = "elm.uc.edu";
	
	// Logging Config
	private static Level logLevel = Level.DEBUG;
	final public static String LOGFILE = "mobilePrinting.log";
	private static Logger log = Logger.getLogger("MobilePrinting");
	final public static Logger LOGGER = setLogging();
	
	// XML Files
	final public static String XMLFILE = "printers.xml";
	final public static String XMLVALIDATE = "printer.xsd";
	
	// The keys to use for the getIconsHashMap
	final public static String[] trayicon = { "trayicon_norm", "trayicon_error", "trayicon_prog0", 
											  "trayicon_prog1", "trayicon_prog2", "trayicon_prog3", 
											  "trayicon_test" };
	// Image Files
	final public static HashMap<String, String> IconArray = getIcons();
	final public static String MAINIMAGE = "MainImage200_t.gif";
	
	
	// Configuration Files 
	final public static String DEFAULT_CONF = "defaults.xml";
	final public static String USER_CONF    = "user.xml";
	final public static String CURRENT_PRINTER = "current.xml";
	
	final public static String DBNAME   = "UsageData";
	final public static String PORTNAME = "MobilePrinter";
	final public static String WINSCRIPTSPATH = getPrinterScriptsPath();
	final public static String APPNAME = "MobilePrinting";
	final public static String MAC_APPNAME = APPNAME + ".app";
	final public static String WIN_APPNAME = APPNAME + ".exe";
	final public static String START_PATH = getAppname();
	final public static String WINDRIVERUNC = USERSPACE + "drivers" + DELIM + "HPUniversal" + DELIM + "hpcu094d.inf";
	
	public static String default_prefs = PREFS + DELIM + DEFAULT_CONF;
	public static String user_prefs = PREFS + DELIM + USER_CONF;
	
	private Configurator() { } // Make this a non-instantiable class

	/**
	 * Method that sets up adn returns a HashMap of files needed
	 * @return Hashmap<String, String> whose key is the filename 
	 * 		   and value is the absoulte path in the filesystem that the 
	 * 		   file should be installed
	 */
	public static HashMap<String, String> getFilesMap(){
		HashMap<String, String> hm = new HashMap<String, String>();
		for(int i = 0; i < trayicon.length; i++) {
			hm.put(IconArray.get(trayicon[i]), ICONS + DELIM + IconArray.get(trayicon[i]));
		}
		return hm;
	}
	
	/**
	 * Method that sets up and returns a HashMap of directories needed
	 * @return a HashMap whose key is the directory name and
	 * 		   whose value is the absolute path of the directory
	 */
	public static HashMap<String, String> getDirectoryMap(){
		HashMap<String, String> hm = new HashMap<String, String>();
		hm.put("userspace", USERSPACE );
		hm.put( "cache", CACHE );
		hm.put( "prefs", PREFS );
		hm.put( "systemspace", SYSTEMSPACE);
		hm.put( "logs", LOGS );
		hm.put( "ppd", PPD );
		hm.put( "icons", ICONS );
		hm.put( "drivers", DRIVERS);
		hm.put( "scripts", SCRIPTS );
		hm.put( "libs", LIBS );
		
		return hm;
	}
	
	/**
	 * Get the string delimiter for this OS
	 * @return the string delimiter ("\" for Windows, "/" for Mac and Linux)
	 */
	private static String getDelim() {
		String delim = null;
		delim = (OS.equalsIgnoreCase("Linux"))
				|| (OS.equalsIgnoreCase("Mac OS X") || (OS
						.equalsIgnoreCase("SunOS"))) ? "/" : "\\";
		return delim;
	}
	
	private static String getAppname(){
		if(OS.startsWith("Win")){
			return WORKINGDIR + DELIM + WIN_APPNAME;
		} else if(OS.startsWith("Mac")){
			return WORKINGDIR + DELIM + MAC_APPNAME;
		} else {
			return "";
		}
	}
	
	/**
	 * Returns the absoulte path to the specified 'space' 
	 * For the userspace pass 'user' for the systemspace pass 'system'
	 * @param space - which cache directory to get user or system
	 * @return the absolute path to that 'space'
	 * @throws OperatingSystemNotSupportedException 
	 */
	private static String getCache( String space ) {
		String dir = null;
		if (space.equalsIgnoreCase("user")){
			if (OS.equalsIgnoreCase("Linux")) {
				dir = homeDir + "/.ucit/MobilePrinting/";
			} else if (OS.equalsIgnoreCase("Mac OS X")) {
				dir = homeDir + "/Library/Application Support/UCit/MobilePrinting/";
			} else if(OS.startsWith("Win")){
				String appdata = System.getenv("APPDATA");
				dir = appdata + "\\ucit\\MobilePrinting\\";
			} else {
				//throw new OperatingSystemNotSupportedException(OS);
			}
			
		} else if (space.equalsIgnoreCase("system")){
			if (OS.equalsIgnoreCase("Linux")) {
				dir = "/etc/ucit/mobilerinting/";
			} else if(OS.equalsIgnoreCase("Mac OS X")){
				dir = "/Library/Application Support/UCit/MobilePrinting/";
			} else if(OS.startsWith("Win")){
				String progfiles = System.getenv("PROGRAMFILES");
				dir = progfiles + "\\ucit\\MobilePrinting\\";
			} else {
				//throw new OperatingSystemNotSupportedException(OS);
			}			
		}
		return dir;
	}
	
	/**
	 * Get the correct icons based on the OS
	 * @return a HashMap<String, String> whose value is 
	 *         is the string name of the file
	 */
	private static HashMap<String, String> getIcons(){
		
		HashMap<String, String> icons = new HashMap<String, String>();
		for( int i = 0; i < trayicon.length; i++ ) {
			if (OS.startsWith("Win")){
				icons.put(trayicon[i], trayicon[i] + "_win.png");
			} 
			if (OS.startsWith("Mac")){
				icons.put(trayicon[i], trayicon[i] + "_mac.png");
			}
			if (OS.startsWith("Linux")){
				icons.put(trayicon[i], trayicon[i] + "_nix.png");
			}
		}
		
		LOGGER.debug("\n" + icons.toString() + "\n");		
		return icons;
		
	}

	/**
	 * Get the Path to the printer scripts
	 * @return 
	 */
	private static String getPrinterScriptsPath() {
		String dir = "";
		if (OS.equalsIgnoreCase("Linux") || OS.equalsIgnoreCase("Mac OS X")) {
			dir = "";
		} else if (OS.equalsIgnoreCase("Windows XP")) {
			dir = "C:\\Windows\\system32";
		} else if (OS.equalsIgnoreCase("Windows 7")) {
			dir = "C:\\WINDOWS\\system32\\Printing_Admin_Scripts\\en-US";
		}
		return dir;

	}
	

	/**
	 * Setup the logger
	 * @return the LOGGER
	 */
	private static Logger setLogging() {	
		try {
			String logFile = LOGS + DELIM + LOGFILE;
			System.out.println("Setting up Logging for " + logFile + "...");
			PatternLayout layout = new PatternLayout("%d - %c - %p - %m%n");
			RollingFileAppender R = new RollingFileAppender(layout, logFile, false);
			R.setMaxFileSize("500KB");
			R.setMaxBackupIndex(1);

			ConsoleAppender c = new ConsoleAppender(layout);
			log.addAppender(R);
			log.addAppender(c);
			log.setLevel(logLevel);
		} catch (Exception e) {
			System.out.println("Caught an error while setting up logging: " + e.toString());
		}
		return log;

	}
	
	

	/**
	 * Get the initial Preferences Object
	 * @return Prefereneces - if user.xml exists than return 
	 * 						  the user prefs else return the default 
	 * 						  prefs
	 */
	public static Preferences getPrefs() {

		PreferencesParser prefParse;
		Preferences prefs;
		File prefs_file = new File(user_prefs);
		if (!prefs_file.exists()) {
			// if a user created file doesn't exist, use the default
			prefs_file = new File(default_prefs);
			if (!prefs_file.exists()) {
				// If the default prefs file doesn't exist then copy it 
				// from the Jar
				Installer i = new Installer();
				i.installFile(Configurator.PREFS + Configurator.DELIM + Configurator.DEFAULT_CONF, default_prefs);
			}
		}

		try {
			prefParse = new PreferencesParser();
			prefs = prefParse.parse(prefs_file);
			return prefs;
		} catch (ParserConfigurationException e) {
			LOGGER.error(e.toString());
		} catch (XPathExpressionException e) {
			LOGGER.error(e.toString());
		} catch (SAXException e) {
			LOGGER.error(e.toString());
		} catch (IOException e) {
			LOGGER.error(e.toString());
		}

		return null;
	}

	
	/**
	 * Set the LogLevel
	 * @param the level to set the log to 
	 */
	public static void setLogLevel( String level ){
		if (level.equalsIgnoreCase("informational")){
			logLevel = Level.INFO;
		} 
		
		if (level.equalsIgnoreCase("error")){
			logLevel = Level.ERROR;
		}
		
		if (level.equalsIgnoreCase("debug")){
			logLevel = Level.DEBUG;
		}
		LOGGER.debug("Resetting Log Settings... to " + logLevel);
		log.setLevel(logLevel);
	}
	

	/**
	 * Set the current zone
	 * @param currentZone
	 */
	public static void setZone(String currentZone) {
		Configurator.currentZone = currentZone;
	}

	
	/**
	 * Get the current zone
	 * @return the zone that the user is currently in
	 */
	public static String getZone() {
		return currentZone;
	}
	
}
